#include <cacheflex.h>
#include <framework.h>
#include <stdlib.h>
#include <string.h>

static framework_api_t default_framework; 

/* This will set above index/store/reclaim/frame to the pointers of sub-modules */
static inline int  register_modules(cacheflex_t *cf,
            cacheflex_kv_ops_t *ops,
            index_interface_t *index,
            store_interface_t *store,
            reclaim_interface_t *reclaim,
            framework_api_t *frame,
            generic_alloc_pt alloc,
            generic_free_pt free)
{
    cf->__kv_ops = ops;
    cf->__index = index;
    cf->__store = store;
    cf->__reclaim = reclaim;
    cf->__frame = frame;
    cf->__alloc = alloc;
    cf->__free = free;
    return 0;

}
typedef struct
{
    char    *name;
    void    *(*get_interface)(generic_alloc_pt alloc,
            generic_free_pt free);
} __mod_interface_t;


#define MODULES(arg) { .name = #arg, .get_interface = arg##_get_interface }
#define DECLARE_MODULES(arg) extern void * arg##_get_interface(generic_alloc_pt alloc, \
        generic_free_pt free)

DECLARE_MODULES(RECLAIM_LRU);
DECLARE_MODULES(STORE_LIBC);
DECLARE_MODULES(INDEX_SOME_HASH);



static __mod_interface_t all_reclaims[] = {
    MODULES(RECLAIM_LRU),
    /* MODULES(RECLAIM_LIRS), */
};
static __mod_interface_t all_stores[] = {
    MODULES(STORE_LIBC),
/*    MODULES(STORE_TCMALLOC), */
};


static __mod_interface_t all_indexes[] = {
    MODULES(INDEX_SOME_HASH),
};


cacheflex_t *cacheflex_setup(
        reclaim_type_t reclaim_type,
        store_type_t store_type,
        index_type_t index_type,
        cacheflex_kv_ops_t *ops,
        generic_alloc_pt alloc,
        generic_free_pt free,
        int64_t limit)
{
    cacheflex_t *cf = NULL;
    index_interface_t *index = NULL;
    store_interface_t *store = NULL;
    reclaim_interface_t *reclaim = NULL;
    
    if (!(cf = (cacheflex_t *)alloc(sizeof(cacheflex_t))))
        return NULL;
    memset(cf, 0, sizeof(cacheflex_t));
    index = (index_interface_t *)all_indexes[index_type].get_interface(alloc, free);
    if (!index)
        goto free_and_out;
    store = (store_interface_t *)all_stores[store_type].get_interface(alloc, free);
    if (!store)
        goto free_and_out;
    reclaim = (reclaim_interface_t *)all_reclaims[reclaim_type].get_interface(alloc, free);
    if (!reclaim)
        goto free_and_out;

    register_modules(cf, ops, index, store, reclaim, 
            &default_framework, alloc, free);
    return cf;

free_and_out:
    if (reclaim)
        free(reclaim);
    if (store)
        free(store);
    if (index)
        free(index);
    if (cf)
        free(cf);
    return NULL;
}



